package com.abaddon.model;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeSupport;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;

import android.graphics.drawable.Drawable;

import com.abaddon.controller.AbaddonItemizedOverlay;
import com.abaddon.controller.AbaddonPropertyChangeValuesHolder;
import com.abaddon.view.Abaddon;
import com.abaddon.view.AbaddonMapView;
import com.abaddon.view.R;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.Overlay;

public class TagManager {

	private static String userName;
	private static String serverAdress;	
	private static int serverPort;
	private static boolean sendPosition = true;
	public static AbaddonMapView mapView;
	
	public static boolean isSendPosition() {
		return sendPosition;
	}

	public static void setSendPosition(boolean sendPosition) {
		TagManager.sendPosition = sendPosition;
	}

	private static HashMap<String, Person> persons = new HashMap<String, Person>();
	private static HashMap<String, Place> places = new HashMap<String, Place>();
	
	private static Abaddon mAbaddon;
	
	private static AbaddonItemizedOverlay itemizedOverlay;
	private static AbaddonDatabase database = null;
	
	public static AbaddonItemizedOverlay getItemizedOverlay() {
		return itemizedOverlay;
	}

	public static int getServerPort() {
		return serverPort;
	}

	public static void setServerPort(int serverPort) {
		TagManager.serverPort = serverPort;
	}
	
	public static Abaddon getAbaddon() {
		return mAbaddon;
	}

	public static AbaddonDatabase getAbaddonDatabase(){
		return database;
	}
	
	public static String getServerAdress() {
		return serverAdress;
	}

	public static void setServerAdress(String serverAdress) {
		TagManager.serverAdress = serverAdress;
	}
	
	/**
	 * Initiates the TagManager, and creates relevant attributes.
	 * @param abaddon
	 */
	public static void init(Abaddon abaddon){
		mAbaddon = abaddon;
		Drawable drawable = abaddon.getResources().getDrawable(R.drawable.blob_me);
		
		itemizedOverlay = new AbaddonItemizedOverlay(drawable, abaddon);
		
		mapView = (AbaddonMapView) abaddon.findViewById(R.id.abaddonMapview);

		mapView.startLongTouchThread(abaddon);
		mapView.setBuiltInZoomControls(true);
		mapView.setClickable(true);

		// Overlay-stuff
		List<Overlay> mapOverlays = mapView.getOverlays();
		mapOverlays.add(itemizedOverlay);
		
		database = new AbaddonDatabase();
		List<Place> placesFromFile = database.getAllPlaces();
		if (placesFromFile != null){
			for(int i = 0; i<placesFromFile.size(); i++) {
				updatePlace(placesFromFile.get(i));
			}
		}
		
		//Check settings in database not null
		String portHolder = TagManager.getAbaddonDatabase().getSetting("serverPort");
		String adressHolder = TagManager.getAbaddonDatabase().getSetting("serverAdress");
		String userHolder = TagManager.getAbaddonDatabase().getSetting("userName");
		String displayHolder = TagManager.getAbaddonDatabase().getSetting("display");
		
		if(portHolder==null){
			portHolder = "2603";
		}
		if(adressHolder==null){
			adressHolder = "46.239.121.170";
		}
		if(userHolder==null){
			userHolder = "Mr. Smith";
		}
		if(displayHolder==null){
			displayHolder = "true";
		}
		
		//Use settings in database
		setServerAdress(adressHolder);
		setServerPort(Integer.parseInt(portHolder));
		setUserName(userHolder);
		setSendPosition((boolean) displayHolder.equals("true"));
		
		String sendPositionString = "true";
		if (sendPosition==false){
			sendPositionString = "false";
		}
		
		getAbaddonDatabase().addSetting("userName", userName);
		getAbaddonDatabase().addSetting("display", sendPositionString);
		getAbaddonDatabase().addSetting("serverAdress", serverAdress);
		getAbaddonDatabase().addSetting("serverPort", "" + serverPort);
	
	}
	
	/**
	 * Updates the persons position
	 * 
	 * @param name The person that you want to update.
	 * @param latitude The latitude of the person.
	 * @param longitude The longitude of the person.
	 */
	public static void updatePerson(String name, int latitude, int longitude){
		if(persons.containsKey(name)){
			Person person = persons.get(name);
			person.setPoint(new GeoPoint(latitude, longitude));
		}else{
			Person person = new Person(new GeoPoint(latitude, longitude), name, "");
			addTag(person);
		}
		
		PropertyChangeEvent ae = new PropertyChangeEvent(mAbaddon, AbaddonPropertyChangeValuesHolder.INVALIDATE, mAbaddon, null);
		
		PropertyChangeSupport pcs = new PropertyChangeSupport(mAbaddon);
		
		pcs.addPropertyChangeListener(mAbaddon);
		pcs.firePropertyChange(ae);
	}
	
	/**
	 * Updates the place with the same name as the parameter.
	 * Adds the Place if it doesn't already exist.
	 * 
	 * @param place The place you want to update/add with the parameters changed.
	 */
	public static void updatePlace(Place place){
		String name = place.getTitle();
		if(places.containsKey(name)){
			Place oldPlace = places.get(name);
			oldPlace.setTitle(place.getTitle());
			oldPlace.setSnippet(place.getSnippet());
			oldPlace.setPoint(place.getPoint());
			oldPlace.setCategories(place.getCategoriesArray());
			database.addPlace(place);
		
		}else{
			addTag(place);
			database.addPlace(place);
		}
	}
	
	/**
	 * Updates the title of a place
	 * 
	 * @param oldTitle The old title.
	 * @param newTitle The new title.
	 */
	public static void updatePlaceTitle(String oldTitle, String newTitle){
		if(places.containsKey(oldTitle)){
			Place oldPlace = places.get(oldTitle);
			Place place = new Place(oldPlace.getPoint(), newTitle, oldPlace.getSnippet(), oldPlace.getCategoriesArray());
			database.removePlace(oldTitle);
			removePlace(oldTitle);
			updatePlace(place);
			database.addPlace(place);
		}
	}
	
	/**
	 * Updates the name of a Person.
	 * 
	 * @param oldTitle The old name of the person.
	 * @param newTitle The new name of the person.
	 */
	public static void updatePersonTitle(String oldTitle, String newTitle){
		if(persons.containsKey(oldTitle)){
			Person oldPerson = persons.get(oldTitle);
			oldPerson.setTitle(newTitle);
			persons.remove(oldTitle);
			persons.put(newTitle, oldPerson);
		}
	}
	
	/**
	 * Adds a tag.
	 *
	 * @param tag The tag to be added(type should be Place or Person)
	 */
	public static void addTag(Tag tag){
		itemizedOverlay.addOverlay(tag);
		
		if(tag instanceof Place){
			Drawable drawable = mAbaddon.getResources().getDrawable(R.drawable.blob_place);
			AbaddonItemizedOverlay.changeMarker(drawable, tag);
			places.put(tag.getTitle(), (Place) tag);
		} else if(tag instanceof Person){
			Drawable drawable;
			if(tag.getTitle().equals(TagManager.getUserName()))
				drawable = mAbaddon.getResources().getDrawable(R.drawable.blob_me);
			else
				drawable = mAbaddon.getResources().getDrawable(R.drawable.blob_other);
			AbaddonItemizedOverlay.changeMarker(drawable, tag);
			persons.put(tag.getTitle(), (Person)tag);
		}
	}
	
	/**
	 * Gets a person by name.
	 * 
	 * @param name The name of the person you want to get.
	 * @return The person or null if there is no person with that name.
	 */
	public static Person getPerson(String name){
		if (persons.containsKey(name))
			return persons.get(name);
		else
			return null;
	}
	
	/**
	 * Gets a place by name.
	 * 
	 * @param name The name of the place you want to get.
	 * @return The place or null if there is no place with that name.
	 */
	public static Place getPlace(String name){
		if (places.containsKey(name))
			return places.get(name);
		else
			return null;
	}

	public static String getUserName() {
		return userName;
	}

	public static void setUserName(String userName) {
		TagManager.userName = userName;
	}
	
	/**
	 * Get places by category.
	 * 
	 * @param category the category you are interested in.
	 * @return A list with all the places that have the category.
	 */
	public static List<Place> getPlaces(String category){
		
		List<Place> returnList = new ArrayList<Place>();
		Set<String> keys = places.keySet();
		
		for (String key : keys) {
			if(places.get(key).getCategoriesList().contains(category)){
				returnList.add(places.get(key));
			}
		}

		return returnList;
	}
	
	/**
	 * Get places by categories.
	 * 
	 * @param categories A list of the categories you are interested in.
	 * @return A list with all the places that have at least one of the categories specified.
	 */
	public static List<Place> getPlaces(List<String> categories){
		
		List<Place> returnList = new ArrayList<Place>();
		for(int i = 0; i<categories.size(); i++){
			returnList.addAll(getPlaces(categories.get(i)));
		}
		return returnList;
	}
	
	/**
	 * Removes the place specified
	 * 
	 * @param name The name of the place to be removed
	 */
	public static void removePlace(String name){
		
		if(places.containsKey(name)){
			database.removePlace(name);
			
			PropertyChangeEvent ae = new PropertyChangeEvent(name, AbaddonPropertyChangeValuesHolder.REMOVEPLACE, itemizedOverlay, places.get(name));
			PropertyChangeSupport pcs = new PropertyChangeSupport(TagManager.getAbaddon());
			pcs.addPropertyChangeListener(TagManager.getAbaddon());
			pcs.firePropertyChange(ae);
			//itemizedOverlay.removeTag(places.get(name));
			
			places.remove(name);
		}
	}
	
	/**
	 * Removes the person specified
	 * 
	 * @param name The name of the person to be removed
	 */
	public static void removePerson(String name){
		if(persons.containsKey(name)){
			itemizedOverlay.removeTag(persons.get(name));
			PropertyChangeEvent ae = new PropertyChangeEvent(name, AbaddonPropertyChangeValuesHolder.REMOVEPERSON, itemizedOverlay, persons.get(name));
			PropertyChangeSupport pcs = new PropertyChangeSupport(TagManager.getAbaddon());
			pcs.addPropertyChangeListener(TagManager.getAbaddon());
			pcs.firePropertyChange(ae);
			persons.remove(name);
		}
	}
	
	/**
	 * Removes all persons except the user
	 */
	public static void removeAllPersons(){
		Set<String> keySet = persons.keySet();
		
		for (String key : keySet) {
			if(!key.equals(userName))
				removePerson(key);
		}
	}

}
